from datetime import datetime
import redis
from django.core.cache import cache
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from rest_framework.views import APIView
from zhipuai import ZhipuAI
from course.models import QnA, exam_topic, work_topic
from course.service.text_preprocessing import pre_procession_text
from course_planning.settings import BASE_DIR
import os
from mycelery.sms.tasks import save_to_database
from .models import work, exam
from .mongo_models import UserCourseView
from .service.recommend import (time_decay_collaborative_filtering, recommend_work, recommend_exam)
from .service.search import search
from .service.serializers import base_examSerializers, base_workSerializers, exam_topicSerializers, \
    work_topicSerializers, ESerializer, WSerializer
import random
import time
import requests

STOPWORDS_FIST = os.path.join(BASE_DIR, 'course/service/hit_stopwords.txt')


# Create your views here.


class question_cutView(APIView):
    authentication_classes = []  # 取消全局认证(暂时)

    def post(self, request):
        # question = request.data['question']
        question = request.data.get('question')
        user_id = request.data.get('user_id')
        if question is None:
            planning = QnA(question=question, user_id=user_id)
            planning.save()
            text = pre_procession_text(question)
            return Response({'code': 200, 'msg': '成功', 'data': text})
        else:
            return Response({'code': 404, 'msg': '问题不能为空，请输入您的问题'})


def ask_zhipu_ai(question):
    # 初始化用户端
    client = ZhipuAI(api_key='db9c3da84bba18660d5727d78d7ee1f2.zAJfSV1M4tEupkhX')

    # 创建聊天完成请求
    response = client.chat.completions.create(
        model='glm-4',
        messages=[
            {"role": "user", "content": question},
        ],
    )

    # 从响应中获取回答内容
    resource_text = response.choices[0].message.content
    return resource_text


class generate_answer(APIView):

    def post(self, request):
        try:
            question = request.data.get('question')
            user = request.user.get('user_id')
            if question is not None:
                answer = ask_zhipu_ai(question)
                planning = QnA(question=question, user_id=user, answer=answer)
                planning.save()
                return Response({'code': 200, 'msg': '成功', 'data': answer})
        except Exception as e:
            return Response({'code': 404, 'msg': str(e)})  # 打印出现的问题

    if __name__ == "__main__":
        api_key = "db9c3da84bba18660d5727d78d7ee1f2.zAJfSV1M4tEupkhX"


# 搜索后根据搜索内容进行推荐（还没有做到模糊查询后进行推荐，后续要改进）
# 另外，如果想进行像淘宝等app那样的首页推送，就不能基于内容进行推送，而是要基于行为进行推送或者是使用协同过滤
# 这两种都无疑需要知道用户对某一“信息”的浏览时间，点赞，收藏等有效信息（或是用户在智能问答系统内检索他提过的问题作为数据）
# 只有先有基于此的行为数据，才可以使用上述两个算法进行首页推送
# class tfidf_(APIView):
#     authentication_classes = []  # 取消全局认证(暂时)
#
#     def post(self, request):
#         # con = pymysql.connect(host='localhost', user='root', password='123456', database='course_planning',
#         #                      charset='utf8mb4')
#         # sql = "select exam.exam_name, exam_topic.Bquestion_content from exam left join exam_topic on exam.exam_id = exam_topic.exam_id"
#         # exam = pd.read_sql(sql, con)
#         # indices = pd.Series(exam.index, index=exam['exam_name']).drop_duplicates()
#         result = content_based_recommendation(exam_name=request.data['exam_name'])
#         return Response({'code': 200, 'msg': '推荐试卷如下', 'data': result})


# 保存用户浏览课程时间进mongodb数据库，前端需要传课程id，浏览时间
# 改为将数据发送至kafka，再在kafka内将数据保存进数据库
class record_course_view(APIView):

    def post(self, request):
        try:
            exam_id = request.data.get('exam_id')
            work_id = request.data.get('work_id')
            view_time = request.data.get('view_time')
            user_id = request.user.get('user_id')  # 从jwt取用户id
            if user_id is None:
                return Response({'code': '404', 'msg': '用户不存在'})
            data = dict(exam_id=exam_id, work_id=work_id, view_time=view_time, user_id=user_id)
            save_to_database(data)
            return Response({'code': 200, 'msg': '发送成功'})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# # 新建一个kafka消费者，拉取“recommendResult”主题的推荐内容
# consumer = KafkaConsumer(
#     'recommendResult',
#     bootstrap_servers=['localhost:9092'],
#     auto_offset_reset='latest',
#     enable_auto_commit=True
# )


# 返回推荐结果
class recommendationView(APIView):
    def post(self, request):
        try:
            result_exam = []
            result_work = []
            result_dict = {}
            # 从Mongodb获取该用户的最近的十个浏览行为
            behavior_data = UserCourseView.objects(user_id=request.user.get('user_id')).order_by("-date")[:10]
            # 用户是新用户则随机返回
            if not behavior_data:
                return self.random_data()
            for data in behavior_data:
                # 区分开作业id与试卷id，避免推荐返回结果时分辨不清id
                if data.exam_id:
                    result_exam.append({
                        "user_id": data.user_id,
                        "exam_id": data.exam_id,
                        "view_time": data.view_time
                    })
                if data.work_id:
                    result_work.append({
                        "user_id": data.user_id,
                        "work_id": data.work_id,
                        "view_time": data.view_time
                    })
            user_id = request.user.get('user_id')
            # 调用函数两次，区分开作业和试卷
            if result_exam:
                user_item_matrix1 = time_decay_collaborative_filtering(behavior_data=result_exam, item_id="exam_id")
                recommendations1 = recommend_exam(user_id, user_item_matrix1)
                exam_ids = list(recommendations1)
                recommendations1 = exam.objects.filter(exam_id__in=exam_ids)
                data = base_examSerializers(instance=recommendations1, many=True)
                result_dict["recommendations1"] = data.data
            if result_work:
                user_item_matrix2 = time_decay_collaborative_filtering(behavior_data=result_work, item_id="work_id")
                recommendations2 = recommend_work(user_id, user_item_matrix2)
                work_ids = list(recommendations2)
                recommendations2 = work.objects.filter(work_id__in=work_ids)
                data = base_workSerializers(instance=recommendations2, many=True)
                result_dict["recommendations2"] = data.data
            return Response({'code': 200, 'msg': result_dict})
        except Exception as e:
            return self.random_data()

    def random_data(self):
        random_numbers = random.sample(range(1, 20 + 1), 5)
        random_exam = exam.objects.filter(exam_id__in=random_numbers)
        random_work = work.objects.filter(work_id__in=random_numbers)
        exam_data = base_examSerializers(instance=random_exam, many=True)
        work_data = base_workSerializers(instance=random_work, many=True)
        merged_data = []
        merged_data.extend(exam_data.data)
        merged_data.extend(work_data.data)
        return Response({'code': 200, 'msg': merged_data})


# 模糊查询
class SearchView(APIView):
    def post(self, request):
        try:
            keyword = request.data.get("keyword")
            if keyword:
                return Response({'code': 200, 'msg': search(keyword=keyword)})
            return Response({'code': 404, 'msg': '请输入关键词'})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 获取时间进行排序
def get_time(exam_id, user_id):
    user = UserCourseView.objects.filter(user_id=user_id, exam_id=exam_id)
    time = user.view_data
    return time


class Pagination(PageNumberPagination):
    page_size = 3  # 每页的数据量
    page_size_query_param = 'page_size'  # 前端发送的每页数目关键字名，默认为None
    max_page_size = 20  # 最大页数


# 浏览历史(按时间排序)
class browsing_historyView(APIView):
    # 返回浏览历史
    def post(self, request):
        try:
            exam_ids = []
            work_ids = []
            user_data = UserCourseView.objects(user_id=request.user.get('user_id'))
            for i in user_data:
                if i.exam_id:
                    exam_ids.append(i.exam_id)
                if i.work_id:
                    work_ids.append(i.work_id)
            exams = exam.objects.filter(exam_id__in=exam_ids)
            works = work.objects.filter(work_id__in=work_ids)
            serializer_exams = base_examSerializers(instance=exams, many=True)
            serializer_works = base_workSerializers(instance=works, many=True)
            # 加入对应时间
            final_data = []
            for exam_data in serializer_exams.data:
                exam_id = exam_data.get("exam_id")
                exam_date = UserCourseView.objects(exam_id=exam_id).first().date
                exam_data["view_date"] = exam_date
                final_data.append(exam_data)
            for work_data in serializer_works.data:
                work_id = work_data.get("work_id")
                work_date = UserCourseView.objects(work_id=work_id).first().date
                work_data["view_date"] = work_date
                final_data.append(work_data)
            # 按照时间信息对数据进行排序
            sorted_data = sorted(final_data, key=lambda x: x.get('view_date'), reverse=True)
            paginator = Pagination()
            paginated_data = paginator.paginate_queryset(sorted_data, request)
            return Response({'code': 200, 'msg': paginated_data})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 删除全部浏览历史
class browsing_historyAllDeleteView(APIView):
    def delete(self, request):
        try:
            user_data = UserCourseView.objects(user_id=request.user.get('user_id')).delete()
            if user_data:
                return Response({'code': 200, 'msg': '删除成功'})
            return Response({'code': 404, 'msg': '历史浏览记录不存在'})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 搜索浏览历史
class browsing_historySearchView(APIView):
    def post(self, request):
        try:
            keyword = request.data.get('keyword')
            if keyword:
                user_data = UserCourseView.objects(user_id=request.user.get('user_id'))
                # 通过关键词搜索到相关资源
                result = search(keyword=keyword)
                # 判断搜到的相关资源是否在浏览历史中
                # 先提取出相关资源的作业id与试卷id，再判断(work_id与exam_id都有可能是多个值，且result是列表)
                work_ids = [item.get('work_id') for item in result if 'work_id' in item]
                exam_ids = [item.get('exam_id') for item in result if 'exam_id' in item]
                results = []
                # 提取出浏览历史中过滤后符合的对象
                for data in user_data:
                    if data.work_id in work_ids or data.exam_id in exam_ids:
                        results.append(data)
                # 从对象中提取出确定的id值
                results_id = []
                for i in results:
                    temp_result = {}
                    for item in i:
                        if 'work_id' in item:
                            temp_result['work_id'] = i.work_id
                        if 'exam_id' in item:
                            temp_result['exam_id'] = i.exam_id
                    results_id.append(temp_result)
                # 根据id值查找并返回
                workIds = []
                for i in results_id:
                    workIds.append(i.get('work_id'))
                same_id = work.objects.filter(work_id__in=workIds)
                work_topic_result = base_workSerializers(instance=same_id, many=True)
                examIds = []
                for i in results_id:
                    examIds.append(i.get('exam_id'))
                same_id = exam.objects.filter(exam_id__in=examIds)
                exam_topic_result = base_examSerializers(instance=same_id, many=True)
                # 加入对应时间
                merged_data = []
                for exam_data in exam_topic_result.data:
                    exam_id = exam_data.get("exam_id")
                    exam_date = UserCourseView.objects(exam_id=exam_id).first().date
                    exam_data["view_date"] = exam_date
                    merged_data.append(exam_data)
                for work_data in work_topic_result.data:
                    work_id = work_data.get("work_id")
                    work_date = UserCourseView.objects(work_id=work_id).first().date
                    work_data["view_date"] = work_date
                    merged_data.append(work_data)
                paginator = Pagination()
                paginated_data = paginator.paginate_queryset(merged_data, request)
                if not merged_data:
                    return Response({'code': 404, 'msg': '没有查找到，换个关键词试试'})
                return Response({'code': 200, 'msg': paginated_data})
            return Response({'code': 404, 'msg': '请输入关键词'})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 删除单个特定的浏览历史
class browsing_historyDeleteView(APIView):
    def delete(self, request):
        try:
            work_id = request.data.get('work_id')
            exam_id = request.data.get('exam_id')
            if not work_id and not exam_id:
                return Response({'code': 404, 'msg': '缺少必要参数work_id或exam_id'})
            user_id = request.user.get('user_id')
            if work_id:
                if UserCourseView.objects(user_id=user_id, work_id=work_id).first():
                    UserCourseView.objects(user_id=user_id, work_id=work_id).delete()
                    return Response({'code': 200, 'msg': '删除成功'})
                else:
                    return Response({'code': 404, 'msg': '记录不存在'})
            if exam_id:
                if UserCourseView.objects(user_id=user_id, exam_id=exam_id).first():
                    UserCourseView.objects(user_id=user_id, exam_id=exam_id).delete()
                    return Response({'code': 200, 'msg': '删除成功'})
                else:
                    return Response({'code': 404, 'msg': '记录不存在'})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 课程详情
class course_detailsView(APIView):
    authentication_classes = []

    def post(self, request):
        try:
            ids = request.data.get('id')
            name = request.data.get('name')
            Detail = work.objects.filter(work_id=ids, work_name=name).first()
            if not Detail:
                Detail = exam.objects.filter(exam_id=ids, exam_name=name).first()
                if not Detail:
                    return Response({'code': 404, 'msg': '查询失败'})
                else:
                    examDetail = exam_topic.objects.filter(exam_id=ids)
                    examDetail_serializer = exam_topicSerializers(instance=examDetail, many=True)
                    return Response({'code': 200, 'msg': examDetail_serializer.data})
            else:
                workDetail = work_topic.objects.filter(work_id=ids)
                examDetail_serializer = work_topicSerializers(instance=workDetail, many=True)
                return Response({'code': 200, 'msg': examDetail_serializer.data})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 试卷点赞
class ExamLikeView(APIView):
    def post(self, request):
        try:
            exam_id = request.data.get('exam_id')
            user_id = request.user.get('user_id')
            # 构建试卷点赞缓存键
            cache_key = f'user:{user_id}:liked_exams'
            # 获取底层的 Redis 连接对象
            redis_conn = cache.client.get_client()
            timestamp = int(time.time())
            # 检查用户是否已经点过赞
            if redis_conn.zscore(cache_key, exam_id):
                data = redis_conn.zrem(cache_key, exam_id)
                return Response({'code': 404, 'msg': '已取消点赞', 'data': data})

            # 记录用户点赞
            data = redis_conn.zadd(cache_key, {exam_id: timestamp})
            return Response({'code': 200, 'msg': '点赞成功', 'data': data})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 作业点赞
class WorkLikeView(APIView):
    def post(self, request):
        try:
            work_id = request.data.get('work_id')
            user_id = request.user.get('user_id')
            # 构建试卷点赞缓存键
            cache_key = f'user:{user_id}:liked_works'
            # 获取底层的 Redis 连接对象
            redis_conn = cache.client.get_client()
            timestamp = int(time.time())
            # 检查用户是否已经点过赞
            if redis_conn.zscore(cache_key, work_id):
                data = redis_conn.zrem(cache_key, work_id)
                return Response({'code': 404, 'msg': '已取消点赞', 'data': data})
            # 记录用户点赞
            data = redis_conn.zadd(cache_key, {work_id: timestamp})
            return Response({'code': 200, 'msg': '点赞成功', 'data': data})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 获取作业的时间戳并且转换成标准时间
def Lget_timestamp_from_work_id(work_id, user_id):
    try:
        works_cache_key = f'user:{user_id}:liked_works'  # 作业点赞缓存键
        redis_conn = cache.client.get_client()
        # 获取用户点赞的作业及对应的时间戳
        liked_works_with_timestamp = redis_conn.zrange(works_cache_key, 0, -1, withscores=True, desc=True)
        # 提取作业ID和时间戳信息
        liked_works = [{'work_id': item.decode('utf-8'), 'timestamp': timestamp} for item, timestamp in
                       liked_works_with_timestamp]
        for i in liked_works:
            if int(i['work_id']) == work_id:
                i['time'] = datetime.fromtimestamp(i['timestamp'])
                i['time'] = i['time'].strftime('%Y-%m-%dT%H:%M:%S.%f')
                return i['time']
    except work.DoesNotExist:
        return None


# 获取试卷的时间戳并且转换成标准时间
def Lget_timestamp_from_exam_id(exam_id, user_id):
    try:
        exams_cache_key = f'user:{user_id}:liked_exams'  # 作业点赞缓存键
        redis_conn = cache.client.get_client()
        # 获取用户点赞的试卷及对应的时间戳
        liked_exams_with_timestamp = redis_conn.zrange(exams_cache_key, 0, -1, withscores=True, desc=True)
        # 提取试卷ID和时间戳信息
        liked_exams = [{'exam_id': item.decode('utf-8'), 'timestamp': timestamp} for item, timestamp in
                       liked_exams_with_timestamp]
        for i in liked_exams:
            if int(i['exam_id']) == exam_id:
                i['time'] = datetime.fromtimestamp(i['timestamp'])
                i['time'] = i['time'].strftime('%Y-%m-%dT%H:%M:%S.%f')
                return i['time']
    except exam.DoesNotExist:
        return None


# 查看用户点赞内容
class UserLikeView(APIView):

    def post(self, request):
        try:
            user_id = request.user.get('user_id')  # 获取用户ID
            exams_cache_key = f'user:{user_id}:liked_exams'  # 试卷点赞缓存键
            works_cache_key = f'user:{user_id}:liked_works'  # 作业点赞缓存键
            # 获取底层的 Redis 连接对象
            redis_conn = cache.client.get_client()
            # 获取用户点赞的作业及对应的时间戳
            liked_works_with_timestamp = redis_conn.zrange(works_cache_key, 0, -1, withscores=True, desc=True)
            # 提取作业ID和时间戳信息
            liked_works = [{'work_id': item.decode('utf-8'), 'timestamp': timestamp} for item, timestamp in
                           liked_works_with_timestamp]
            # 获取用户点赞的试卷及对应的时间戳
            liked_exams_with_timestamp = redis_conn.zrange(exams_cache_key, 0, -1, withscores=True, desc=True)
            # 提取试卷ID和时间戳信息
            liked_exams = [{'exam_id': item.decode('utf-8'), 'timestamp': timestamp} for item, timestamp in
                           liked_exams_with_timestamp]
            # 查询用户点赞的试卷作业信息
            exams = exam.objects.filter(exam_id__in=[int(item['exam_id']) for item in liked_exams])
            exams = ESerializer(exams, many=True).data
            works = work.objects.filter(work_id__in=[int(item['work_id']) for item in liked_works])
            works = WSerializer(works, many=True).data
            for item in works:
                item['time'] = Lget_timestamp_from_work_id(item['work_id'], user_id)
            for item in exams:
                item['time'] = Lget_timestamp_from_exam_id(item['exam_id'], user_id)
            # 合并点赞数据
            liked_items = works + exams
            # 将字节成员解码为字符串，并拆分为试卷ID和时间戳，然后排序
            sorted_liked_items = sorted(liked_items, key=lambda x: x['time'], reverse=True)
            paginator = Pagination()
            like_data = paginator.paginate_queryset(sorted_liked_items, request)
            # 如果用户点赞列表为空，返回空列表；否则返回点赞列表数据
            if like_data:
                return Response({'code': 200, 'msg': '正在加载中', 'data': like_data})
            else:
                return Response({'code': 404, 'msg': '用户点赞列表为空', 'data': []})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 试卷收藏
class ExamFavoriteView(APIView):
    def post(self, request):
        try:
            exam_id = request.data.get('exam_id')
            user_id = request.user.get('user_id')
            # 构建试卷收藏缓存键
            cache_key = f'user:{user_id}:favorite_exams'
            # 获取底层的 Redis 连接对象
            redis_conn = cache.client.get_client()
            timestamp = int(time.time())
            # 检查用户是否已经收藏
            if redis_conn.zscore(cache_key, exam_id):
                data = redis_conn.zrem(cache_key, exam_id)
                return Response({'code': 404, 'msg': '已取消收藏', 'data': data})
            # 记录用户收藏
            data = redis_conn.zadd(cache_key, {exam_id: timestamp})
            return Response({'code': 200, 'msg': '收藏成功', 'data': data})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 作业收藏
class WorkFavoriteView(APIView):

    def post(self, request):
        try:
            work_id = request.data.get('work_id')
            user_id = request.user.get('user_id')
            # 构建试卷收藏缓存键
            cache_key = f'user:{user_id}:favorite_works'
            # 获取底层的 Redis 连接对象
            redis_conn = cache.client.get_client()
            timestamp = int(time.time())
            # 检查用户是否已经收藏
            if redis_conn.zscore(cache_key, work_id):
                data = redis_conn.zrem(cache_key, work_id)
                return Response({'code': 404, 'msg': '已取消收藏', 'data': data})
            # 记录用户收藏
            data = redis_conn.zadd(cache_key, {work_id: timestamp})
            return Response({'code': 200, 'msg': '收藏成功', 'data': data})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 获取作业的时间戳并且转换成标准时间
def Fget_timestamp_from_work_id(work_id, user_id):
    try:
        works_cache_key = f'user:{user_id}:favorite_works'  # 作业点赞缓存键
        redis_conn = cache.client.get_client()
        # 获取用户收藏的作业及对应的时间戳
        favorite_works_with_timestamp = redis_conn.zrange(works_cache_key, 0, -1, withscores=True, desc=True)
        # 提取作业ID和时间戳信息
        favorite_works = [{'work_id': item.decode('utf-8'), 'timestamp': timestamp} for item, timestamp in
                          favorite_works_with_timestamp]
        for i in favorite_works:
            if int(i['work_id']) == work_id:
                i['time'] = datetime.fromtimestamp(i['timestamp'])
                return i['time']
    except work.DoesNotExist:
        return None


# 获取试卷的时间戳并且转换成标准时间
def Fget_timestamp_from_exam_id(exam_id, user_id):
    try:
        exams_cache_key = f'user:{user_id}:favorite_exams'  # 作业点赞缓存键
        redis_conn = cache.client.get_client()
        # 获取用户收藏的试卷及对应的时间戳
        favorite_exams_with_timestamp = redis_conn.zrange(exams_cache_key, 0, -1, withscores=True, desc=True)
        # 提取试卷ID和时间戳信息
        favorite_exams = [{'exam_id': item.decode('utf-8'), 'timestamp': timestamp} for item, timestamp in
                          favorite_exams_with_timestamp]
        for i in favorite_exams:
            if int(i['exam_id']) == exam_id:
                i['time'] = datetime.fromtimestamp(i['timestamp'])
                return i['time']
    except exam.DoesNotExist:
        return None


# 查看用户收藏内容
class UserFavoriteView(APIView):

    def post(self, request):
        try:
            user_id = request.user.get('user_id')  # 获取用户ID
            exams_cache_key = f'user:{user_id}:favorite_exams'  # 试卷收藏缓存键
            works_cache_key = f'user:{user_id}:favorite_works'  # 作业收藏缓存键
            # 获取底层的 Redis 连接对象
            redis_conn = cache.client.get_client()
            # 获取用户收藏的作业及对应的时间戳
            favorite_works_with_timestamp = redis_conn.zrange(works_cache_key, 0, -1, withscores=True, desc=True)
            # 提取作业ID和时间戳信息
            favorite_works = [{'work_id': item.decode('utf-8'), 'timestamp': timestamp} for item, timestamp in
                              favorite_works_with_timestamp]
            # 获取用户收藏的试卷及对应的时间戳
            favorite_exams_with_timestamp = redis_conn.zrange(exams_cache_key, 0, -1, withscores=True, desc=True)
            # 提取试卷ID和时间戳信息
            favorite_exams = [{'exam_id': item.decode('utf-8'), 'timestamp': timestamp} for item, timestamp in
                              favorite_exams_with_timestamp]
            # 查询用户收藏的试卷作业信息
            exams = exam.objects.filter(exam_id__in=[int(item['exam_id']) for item in favorite_exams])
            exams = ESerializer(exams, many=True).data
            works = work.objects.filter(work_id__in=[int(item['work_id']) for item in favorite_works])
            works = WSerializer(works, many=True).data
            for item in works:
                item['time'] = Fget_timestamp_from_work_id(item['work_id'], user_id)
            for item in exams:
                item['time'] = Fget_timestamp_from_exam_id(item['exam_id'], user_id)
            # 合并收藏数据
            favorite_items = works + exams
            # 将字节成员解码为字符串，并拆分为试卷ID和时间戳，然后排序
            sorted_favorite_items = sorted(favorite_items, key=lambda x: x['time'], reverse=True)
            paginator = Pagination()
            favorite_data = paginator.paginate_queryset(sorted_favorite_items, request)
            # 如果用户收藏列表为空，返回空列表；否则返回收藏列表数据
            if favorite_data:
                return Response({'code': 200, 'msg': '正在加载中', 'data': favorite_data})
            else:
                return Response({'code': 404, 'msg': '用户收藏列表为空', 'data': []})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 单个用例反馈用户作业点赞收藏,离线缓存情况
class ReflectWLikeAndFavorite(APIView):

    def post(self, request):
        try:
            work_id = request.data.get('work_id')
            user_id = request.user.get('user_id')
            liked_cache_key = f'user:{user_id}:liked_works'
            favorite_cache_key = f'user:{user_id}:favorite_works'
            cache_key = f'user:{user_id}:cached_works'
            redis_conn = cache.client.get_client()
            # 检查用户是否已经点赞
            is_liked = redis_conn.zscore(liked_cache_key, work_id)
            # 检查用户是否已经收藏
            is_favorite = redis_conn.zscore(favorite_cache_key, work_id)
            # 检查用户是否已经离线缓存
            is_cached = redis_conn.zscore(cache_key, work_id)
            return Response({'code': 200, 'liked': is_liked is not None, 'favorite': is_favorite is not None,
                             'cached': is_cached is not None})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 单个用例反馈用户试卷点赞收藏，离线缓存情况
class ReflectELikeAndFavorite(APIView):

    def post(self, request):
        try:
            exam_id = request.data.get('exam_id')
            user_id = request.user.get('user_id')
            liked_cache_key = f'user:{user_id}:liked_exams'
            favorite_cache_key = f'user:{user_id}:favorite_exams'
            cache_key = f'user:{user_id}:cached_exams'
            redis_conn = cache.client.get_client()
            # 检查用户是否已经点赞
            is_liked = redis_conn.zscore(liked_cache_key, exam_id)
            # 检查用户是否已经收藏
            is_favorite = redis_conn.zscore(favorite_cache_key, exam_id)
            # 检查用户是否已经离线缓存
            is_cached = redis_conn.zscore(cache_key, exam_id)
            return Response({'code': 200, 'liked': is_liked is not None, 'favorite': is_favorite is not None,
                             'cached': is_cached is not None})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 离线缓存（数据缓存，返回头信息）
class CacheCourse(APIView):
    def post(self, request):
        try:
            # 网址和头信息
            url = request.data.get('url')
            user_id = request.user.get('user_id')
            redis_conn = cache.client.get_client()
            timestamp = int(time.time())
            exam_id = request.data.get('exam_id')
            work_id = request.data.get('work_id')
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393',
                'Cache-Control': None,
                'Last-Modified': datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
            }
            # 发送 GET 请求
            response = requests.get(url, headers=headers)
            if response.status_code == 200:
                if exam_id:
                    cache_exam_key = f'user:{user_id}:cached_exams'
                    exams = exam.objects.filter(exam_id=exam_id).first()
                    data = ESerializer(exams).data
                    if redis_conn.zscore(cache_exam_key, exam_id):
                        return Response({'code': 404, 'msg': '已缓存', 'data': data})
                    else:
                        redis_conn.zadd(cache_exam_key, {exam_id: timestamp})
                        return Response({'code': 200, 'msg': '缓存成功', 'data': data})
                elif work_id:
                    cache_work_key = f'user:{user_id}:cached_works'
                    works = work.objects.filter(work_id=work_id).first()
                    data = WSerializer(works).data
                    if redis_conn.zscore(cache_work_key, work_id):
                        return Response({'code': 404, 'msg': '已缓存', 'data': data})
                    else:
                        redis_conn.zadd(cache_work_key, {work_id: timestamp})
                        return Response({'code': 200, 'msg': '缓存成功', 'data': data})
            else:
                return Response({'code': 404, 'msg': '缓存失败，请重新尝试'})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 获取作业的时间戳并且转换成标准时间
def Cget_timestamp_from_work_id(work_id, user_id):
    try:
        works_cache_key = f'user:{user_id}:cached_works'
        redis_conn = cache.client.get_client()
        cached_works_with_timestamp = redis_conn.zrange(works_cache_key, 0, -1, withscores=True, desc=True)
        cached_works = [{'work_id': item.decode('utf-8'), 'timestamp': timestamp} for item, timestamp in
                        cached_works_with_timestamp]
        for i in cached_works:
            if int(i['work_id']) == work_id:
                i['time'] = datetime.fromtimestamp(i['timestamp'])
                return i['time']
    except work.DoesNotExist:
        return None


# 获取试卷的时间戳并且转换成标准时间
def Cget_timestamp_from_exam_id(exam_id, user_id):
    try:
        exams_cache_key = f'user:{user_id}:cached_exams'
        redis_conn = cache.client.get_client()
        cached_exams_with_timestamp = redis_conn.zrange(exams_cache_key, 0, -1, withscores=True, desc=True)
        cached_exams = [{'exam_id': item.decode('utf-8'), 'timestamp': timestamp} for item, timestamp in
                        cached_exams_with_timestamp]
        for i in cached_exams:
            if int(i['exam_id']) == exam_id:
                i['time'] = datetime.fromtimestamp(i['timestamp'])
                return i['time']
    except exam.DoesNotExist:
        return None


# 查看用户离线缓存列表
class UserCacheView(APIView):

    def post(self, request):
        try:
            user_id = request.user.get('user_id')
            exams_cache_key = f'user:{user_id}:cached_exams'
            works_cache_key = f'user:{user_id}:cached_works'
            redis_conn = cache.client.get_client()
            cached_works_with_timestamp = redis_conn.zrange(works_cache_key, 0, -1, withscores=True, desc=True)
            cached_works = [{'work_id': item.decode('utf-8'), 'timestamp': timestamp} for item, timestamp in
                            cached_works_with_timestamp]
            cached_exams_with_timestamp = redis_conn.zrange(exams_cache_key, 0, -1, withscores=True, desc=True)
            cached_exams = [{'exam_id': item.decode('utf-8'), 'timestamp': timestamp} for item, timestamp in
                            cached_exams_with_timestamp]
            exams = exam.objects.filter(exam_id__in=[int(item['exam_id']) for item in cached_exams])
            exams = ESerializer(exams, many=True).data
            works = work.objects.filter(work_id__in=[int(item['work_id']) for item in cached_works])
            works = WSerializer(works, many=True).data
            for item in works:
                item['time'] = Cget_timestamp_from_work_id(item['work_id'], user_id)
            for item in exams:
                item['time'] = Cget_timestamp_from_exam_id(item['exam_id'], user_id)
            cached_items = works + exams
            sorted_cached_items = sorted(cached_items, key=lambda x: x['time'], reverse=True)
            if sorted_cached_items:
                return Response({'code': 200, 'msg': '正在加载中', 'data': sorted_cached_items})
            else:
                return Response({'code': 404, 'msg': '用户离线缓存列表为空', 'data': []})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 单个删除离线缓存记录
class DelOneCached(APIView):

    def post(self, request):
        try:
            user_id = request.user.get('user_id')
            exam_id = request.data.get('exam_id')
            work_id = request.data.get('work_id')
            redis_conn = cache.client.get_client()
            if exam_id:
                cache_exam_key = f'user:{user_id}:cached_exams'
                if redis_conn.zscore(cache_exam_key, exam_id):
                    redis_conn.zrem(cache_exam_key, exam_id)
                    return Response({'code': 200, 'msg': '已删除'})
                else:
                    return Response({'code': 404, 'msg': '记录不存在'})
            elif work_id:
                cache_work_key = f'user:{user_id}:cached_works'
                if redis_conn.zscore(cache_work_key, work_id):
                    redis_conn.zrem(cache_work_key, work_id)
                    return Response({'code': 200, 'msg': '已删除'})
                else:
                    return Response({'code': 404, 'msg': '记录不存在'})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})


# 删除全部离线缓存
class DelAllCached(APIView):
    def post(self, request):
        try:
            user_id = request.user.get('user_id')
            redis_conn = cache.client.get_client()
            cache_exam_key = f'user:{user_id}:cached_exams'
            cache_work_key = f'user:{user_id}:cached_works'
            if not redis_conn.exists(cache_exam_key) and not redis_conn.exists(cache_work_key):
                return Response({'code': 404, 'msg': '无任何记录'})
            else:
                if redis_conn.exists(cache_exam_key):
                    exam_keys = redis_conn.zrange(cache_exam_key, 0, -1)  # 获取所有成员
                    for key in exam_keys:
                        redis_conn.zrem(cache_exam_key, key)
                if redis_conn.exists(cache_work_key):
                    work_keys = redis_conn.zrange(cache_work_key, 0, -1)  # 获取所有成员
                    for key in work_keys:
                        redis_conn.zrem(cache_work_key, key)
                return Response({'code': 200, 'msg': '已全部删除'})
        except Exception as e:
            return Response({'code': 404, 'msg': f"系统错误:{e}"})
